#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <iostream>
#include <signal.h>
#include <fcntl.h>

#define BUF_SIZE 512
#define MAX_EVENTS 10
#define MAX_CONN_COUNT 20

int sockets[2];

int setnonblocking(int fd) {
    int old_option = fcntl(fd, F_GETFL);
    int new_option = old_option | O_NONBLOCK;
    fcntl(fd, F_SETFL, new_option);
    return old_option;
}

void addfd(int epollfd, int fd, bool one_shot, int TRIGMode) {
    epoll_event event;
    event.data.fd = fd;

    if (1 == TRIGMode)
        event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
    else
        event.events = EPOLLIN | EPOLLRDHUP;

    if (one_shot)
        event.events |= EPOLLONESHOT;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
    setnonblocking(fd);
}

bool isInterfaceRunning(const std::string& interface) {
    std::string cmd = "ifconfig " + interface + " | grep -o RUNNING";
    char buffer[128];
    std::string result = "";
    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe) return false;
    while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
        result += buffer;
    }
    pclose(pipe);
    return result.find("RUNNING") != std::string::npos;
}

void alarm_handler(int signum) {
    int msg = signum;
    if (!isInterfaceRunning("eth0")) {
        if (signum == SIGALRM) {
            std::cout << "Interface eth1 is down, sending signal to pipe..." << std::endl;
            send(sockets[1], (char *)&msg, 1, 0);
        }
    }
    std::cout << "Received signal: " << msg << std::endl;
    alarm(5);   
}

void initSignalEpoll(int epollfd) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = alarm_handler;
    sigaction(SIGALRM, &sa, NULL);
    alarm(3);
}

int createServerSocket(int listener_port) {
    int server_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP), client_sockfd = -1;
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(listener_port);
    bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    listen(server_sockfd, MAX_CONN_COUNT);
    printf("[debug] listening on %s:%d ...\n", "127.0.0.1", listener_port);
    return server_sockfd;
}

int initEpoll(int server_sockfd, struct epoll_event *ev) {
    int epollfd = epoll_create1(0);
    if (epollfd == -1) {
        printf("[error] epoll error\n");
        exit(EXIT_FAILURE);
    }
    ev->events = EPOLLIN;
    ev->data.fd = server_sockfd;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, server_sockfd, ev) == -1) {
        printf("[error] epoll server_sockfd error\n");
        exit(EXIT_FAILURE);
    }
    return epollfd;
}

void handleConnectSocketData(int server_sockfd, int epollfd, struct epoll_event *ev) {
    printf("[debug] new client connecting...\n");
    struct sockaddr_in client_addr;
    socklen_t clnt_addr_size = sizeof(client_addr);
    int client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &clnt_addr_size);
    if (client_sockfd == -1) {
        printf("[error] accept error\n");
        exit(EXIT_FAILURE);
    }
    ev->events = EPOLLIN | EPOLLET;
    ev->data.fd = client_sockfd;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, client_sockfd, ev) == -1) {
        printf("[error] epoll client_sockfd error\n");
        exit(EXIT_FAILURE);
    }
}

void handleReadSocketData(int client_sockfd, int epollfd, struct epoll_event *ev) {
    printf("[debug] client %d is readable...\n", client_sockfd);
    char buf[BUF_SIZE];
    ssize_t nread;
    memset(buf, 0, sizeof(buf));
    nread = recv(client_sockfd, buf, BUF_SIZE, MSG_DONTWAIT);
    if (nread == -1) {
        printf("[error] recv error\n");
        exit(EXIT_FAILURE);
    } else if (nread == 0) {
        printf("[debug] client exit...\n");
        close(client_sockfd);
    } else {
        int received_size = (int)(strlen(buf));
        printf("<<<< Received request：%s, size: %d\n", buf, received_size);
        ev->events = EPOLLOUT | EPOLLET;
        ev->data.fd = client_sockfd;
        if (epoll_ctl(epollfd, EPOLL_CTL_MOD, client_sockfd, ev) == -1) {
            printf("[error] epoll client_sockfd error\n");
            exit(EXIT_FAILURE);
        }
    }
}

void handleWriteSocketData(int client_sockfd, int epollfd, struct epoll_event *ev) {
    printf("[debug] client %d is writeable...\n", client_sockfd);
    char feedback[] = "WriteResult({ \"nRemoved\" : 1 })";
    printf(">>>> Sending response: %s\n", feedback);
    write(client_sockfd, feedback, sizeof(feedback));
    ev->events = EPOLLIN | EPOLLET;
    ev->data.fd = client_sockfd;
    if (epoll_ctl(epollfd, EPOLL_CTL_MOD, client_sockfd, ev) == -1) {
        printf("[error] epoll client_sockfd error\n");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cerr << "用法: " << argv[0] << "<开放端口>" << std::endl;
        return 1;
    }

    int OPENPORT = std::stoi(argv[1]);
    int server_sockfd = -1, client_sockfd = -1;
    struct epoll_event ev, events[MAX_EVENTS];
    int nfds, epollfd, fd;

    server_sockfd = createServerSocket(OPENPORT);
    socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
    epollfd = initEpoll(server_sockfd, &ev);
    initSignalEpoll(epollfd);

    addfd(epollfd, sockets[0], false, 0);

    while (1) {
        nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        if (nfds < 0 && errno != EINTR)
        {
            printf("[error] epoll error!!!\n");
            break;
        }
        printf("[debug] epoll value is: %d\n", nfds);
        for (fd = 0; fd < nfds; fd++) {
            if (events[fd].data.fd == server_sockfd) {
                handleConnectSocketData(server_sockfd, epollfd, &ev);
            } else if (events[fd].events & EPOLLIN) {
                handleReadSocketData(events[fd].data.fd, epollfd, &ev);
            } else if (events[fd].events & EPOLLOUT) {
                handleWriteSocketData(events[fd].data.fd, epollfd, &ev);
            } else if (events[fd].data.fd == sockets[0]) {
                char received_signal;
                int count = recv(sockets[0], &received_signal, sizeof(received_signal), 0);
                if (count > 0) {
                    for (int i = 0; i < count; ++i) {
                        switch (received_signal) {
                            case SIGALRM: {
                                std::cout << "Received SIGALRM " << std::endl;
                                epoll_ctl(epollfd, EPOLL_CTL_DEL, events[fd].data.fd, NULL);
                                close(events[fd].data.fd);
                                break;
                            }
                            default: {
                                std::cout << "Received Other SIGNAL " << std::endl;
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
    return 0;
}
